diff options
Diffstat (limited to 'examples/portfolio/src/pages/work/[...slug].astro')
-rw-r--r-- | examples/portfolio/src/pages/work/[...slug].astro | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/examples/portfolio/src/pages/work/[...slug].astro b/examples/portfolio/src/pages/work/[...slug].astro new file mode 100644 index 000000000..90eb3ba8d --- /dev/null +++ b/examples/portfolio/src/pages/work/[...slug].astro @@ -0,0 +1,152 @@ +--- +import { type CollectionEntry, getCollection } from 'astro:content'; + +import BaseLayout from '../../layouts/BaseLayout.astro'; + +import ContactCTA from '../../components/ContactCTA.astro'; +import Hero from '../../components/Hero.astro'; +import Icon from '../../components/Icon.astro'; +import Pill from '../../components/Pill.astro'; +import { render } from 'astro:content'; + +interface Props { + entry: CollectionEntry<'work'>; +} + +// This is a dynamic route that generates a page for every Markdown file in src/content/ +// Read more about dynamic routes and this `getStaticPaths` function in the Astro docs: +// https://docs.astro.build/en/core-concepts/routing/#dynamic-routes +export async function getStaticPaths() { + const work = await getCollection('work'); + return work.map((entry) => ({ + params: { slug: entry.id }, + props: { entry }, + })); +} + +const { entry } = Astro.props; +const { Content } = await render(entry); +--- + +<BaseLayout title={entry.data.title} description={entry.data.description}> + <div class="stack gap-20"> + <div class="stack gap-15"> + <header> + <div class="wrapper stack gap-2"> + <a class="back-link" href="/work/"><Icon icon="arrow-left" /> Work</a> + <Hero title={entry.data.title} align="start"> + <div class="details"> + <div class="tags"> + {entry.data.tags.map((t) => <Pill>{t}</Pill>)} + </div> + <p class="description">{entry.data.description}</p> + </div> + </Hero> + </div> + </header> + <main class="wrapper"> + <div class="stack gap-10 content"> + {entry.data.img && <img src={entry.data.img} alt={entry.data.img_alt || ''} />} + <div class="content"> + <Content /> + </div> + </div> + </main> + </div> + <ContactCTA /> + </div> +</BaseLayout> + +<style> + header { + padding-bottom: 2.5rem; + border-bottom: 1px solid var(--gray-800); + } + + .back-link { + display: none; + } + + .details { + display: flex; + flex-direction: column; + padding: 0.5rem; + gap: 1.5rem; + justify-content: space-between; + align-items: center; + } + + .tags { + display: flex; + gap: 0.5rem; + } + + .description { + font-size: var(--text-lg); + max-width: 54ch; + } + + .content { + max-width: 65ch; + margin-inline: auto; + } + + .content > :global(* + *) { + margin-top: 1rem; + } + + .content :global(h1), + .content :global(h2), + .content :global(h3), + .content :global(h4), + .content :global(h5) { + margin: 1.5rem 0; + } + + .content :global(img) { + border-radius: 1.5rem; + box-shadow: var(--shadow-sm); + background: var(--gradient-subtle); + border: 1px solid var(--gray-800); + } + + .content :global(blockquote) { + font-size: var(--text-lg); + font-family: var(--font-brand); + font-weight: 600; + line-height: 1.1; + padding-inline-start: 1.5rem; + border-inline-start: 0.25rem solid var(--accent-dark); + color: var(--gray-0); + } + + .back-link, + .content :global(a) { + text-decoration: 1px solid underline transparent; + text-underline-offset: 0.25em; + transition: text-decoration-color var(--theme-transition); + } + + .back-link:hover, + .back-link:focus, + .content :global(a:hover), + .content :global(a:focus) { + text-decoration-color: currentColor; + } + + @media (min-width: 50em) { + .back-link { + display: block; + align-self: flex-start; + } + + .details { + flex-direction: row; + gap: 2.5rem; + } + + .content :global(blockquote) { + font-size: var(--text-2xl); + } + } +</style> |